﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;

namespace SweetSurvey.Models.Repositories
{
    public class QuestionRepository: RepositoryBase, IQuestionRepository
    {
        #region IRepository<Question,string> Members

        public Question Get(string id, bool detaching = true)
        {
            var context = new SweetSurveyModelContainer();
            var result = context.Questions.Where(q => q.Id.Equals(id, StringComparison.Ordinal)).Single();
            if (detaching) { context.Questions.Detach(result); }
            return result;
        }

        public string Create(Question entity)
        {
            if (string.IsNullOrEmpty(entity.Id)) { entity.Id = RepositoryBase.GenerateRandomId(); }
            var context = new SweetSurveyModelContainer();
            context.Questions.AddObject(entity);
            context.SaveChanges();
            return entity.Id;
        }

        public void Update(Question entity)
        {
            RepositoryBase.Update(entity);
        }

        public void Delete(string id)
        {
            RepositoryBase.Delete(Get(id));
        }

        #endregion

        #region IQuestionRepository Members

        public IQueryable<Question> GetSampleQuestions()
        {
            var results = new List<Question>();
            results.Add(CreateSampleQuestion("Do you like Sweet Survey?", 0,
                "Yes", "No"));
            results.Add(CreateSampleQuestion("Which season do you like best?", 1,
                "Spring", "Summer", "Autumn", "Winter"));
            results.Add(CreateSampleQuestion("What continent do you live on?", 2,
                "Africa", "Aisa", "Antarctica", "Australia", "Europe", "North America", "South America", "I do not live in this planet..."));
            return results.AsQueryable();
        }

        public IQueryable<Question> GetQuestionsBySurveyId(string surveyId)
        {
            return this.GetQuestionsBySurveyId(surveyId, null);
        }

        public void MoveUp(string id)
        {
            var surveyId = this.Get(id).SurveyId;
            var context = new SweetSurveyModelContainer();
            var questions = this.GetQuestionsBySurveyId(surveyId, context).ToList();
            this.RefreshQuestionIndices(questions);
            int currentIndex = this.GetQuestionIndex(questions, id);
            if (currentIndex > 0)
            {
                this.Exchange(questions[currentIndex], questions[currentIndex - 1]);
                context.SaveChanges();
            }
        }

        public void MoveDown(string id)
        {
            var surveyId = this.Get(id).SurveyId;
            var context = new SweetSurveyModelContainer();
            var questions = this.GetQuestionsBySurveyId(surveyId, context).ToList();
            this.RefreshQuestionIndices(questions);
            int currentIndex = this.GetQuestionIndex(questions, id);
            if (currentIndex < questions.Count - 1)
            {
                this.Exchange(questions[currentIndex], questions[currentIndex + 1]);
                context.SaveChanges();
            }
        }

        public bool ValidateSequence(string surveyId, IList<string> questionIds)
        {
            var questions = GetQuestionsBySurveyId(surveyId);
            var ids = GetQuestionsBySurveyId(surveyId).Select(q => q.Id).ToList();
            if (ids.Count != questionIds.Count) { return false; }
            for (int i = 0; i < ids.Count; i++)
            {
                if (!ids[i].Equals(questionIds[i], StringComparison.OrdinalIgnoreCase))
                    return false;
            }
            return true;
        }

        #endregion

        #region Protected Methods

        protected Question CreateSampleQuestion(string title, short index, params string[] options)
        {
            var question = new Question()
            {
                Id = RepositoryBase.GenerateRandomId(),
                SurveyId = string.Empty,
                Title = title,
                Index = index,
            };
            foreach (var option in options)
            {
                question.Options.Add(new Option() { Id = RepositoryBase.GenerateRandomId(), Text = option });
            }
            return question;
        }

        protected IQueryable<Question> GetQuestionsBySurveyId(string surveyId, SweetSurveyModelContainer context)
        {
            if (context == null)
                context = new SweetSurveyModelContainer();
            
            return from q in context.Questions
                   where q.SurveyId.Equals(surveyId, StringComparison.Ordinal)
                   orderby q.Index ascending
                   select q;
        }

        protected void RefreshQuestionIndices(IList<Question> questions)
        {
            for (short i = 0; i < questions.Count; i++)
            {
                var question = questions[i];
                question.Index = i;
            }
        }

        protected short GetQuestionIndex(IList<Question> questions, string id)
        {
            for (short i = 0; i < questions.Count; i++)
            {
                var question = questions[i];
                if (question.Id.Equals(id, StringComparison.Ordinal))
                    return i;
            }
            throw new NullReferenceException();
        }

        protected void Exchange(Question q1, Question q2)
        {
            short index = q1.Index;
            q1.Index = q2.Index;
            q2.Index = index;
        }

        public void DeleteQuestionsBySurveyId(string surveyId)
        {
            var context = new SweetSurveyModelContainer();
            var questions = context.Questions.Where(q => q.SurveyId == surveyId);
            foreach (var q in questions) { context.ObjectStateManager.ChangeObjectState(q, EntityState.Deleted); }
            context.SaveChanges();
        }

        #endregion
    }
}